// import { Graph, Path, Cell } from '@antv/x6'
import { Graph, Path } from '@antv/x6'
import { Selection } from '@antv/x6-plugin-selection'
import { register } from '@antv/x6-react-shape'
import { Stencil } from '@antv/x6-plugin-stencil'
import { Keyboard } from '@antv/x6-plugin-keyboard'
import { Clipboard } from '@antv/x6-plugin-clipboard'
import AlgoNode from './node'

export function createKeyboard(graph: Graph) {
  graph.bindKey('ctrl+c', () => {
    const cells = graph.getSelectedCells()
    if (cells.length) {
      graph.copy(cells)
    }
    return false
  })
  graph.bindKey('ctrl+v', () => {
    if (!graph.isClipboardEmpty()) {
      const cells = graph.paste({ offset: 32 })
      graph.cleanSelection()
      graph.select(cells)
    }
    return false
  })
  graph.bindKey('delete', () => {
    const cells = graph.getSelectedCells()
    if (cells.length) {
      graph.removeCells(cells)
    }
    return false
  })
  graph.bindKey('esc', () => {
    const cells = graph.getSelectedCells()
    if (cells) {
      graph.cleanSelection()
    }
    return false
  })
}

function createNodeWithTemplate(graph: Graph, nodeInfo: Model.NodeInfo) {
  return graph.createNode({
    shape: 'dag-node',
    label: nodeInfo.name,
    attrs: {
    },
    data: {
      ...nodeInfo
    },
    ports: [
      {
        id: `node-${nodeInfo.id}-1`,
        group: "top"
      },
      {
        id: `node-${nodeInfo.id}-2`,
        group: "bottom"
      }
    ]
  })

}

export const initStencil = (graph: Graph, nodes: Model.NodeInfo[]) => {
  let nodeList = nodes;
  if (!nodes) {
    nodeList = [{
      id: 'node-1',
      name: '节点1',
      type: 'node',
      group: 'group1',
      status: 'default',
      nodeConfig: {}
    }]
  }
  // const groups = nodeList.map(nodeInfo => { return { title: nodeInfo.group, name: nodeInfo.group } })
  //使用组进行分类
  const groupMap = nodeList.reduce((acc, node) => {
    if (acc[node.group]) {
      acc[node.group].push(node);
    } else {
      acc[node.group] = [node];
    }
    return acc;
  }, {} as Record<string, Model.NodeInfo[]>)
  const groups = []
  for (let group in groupMap) {
    if (groupMap.hasOwnProperty(group)) {
      groups.push({ "title": group, "name": group })
    }
  }
  const stencil = new Stencil({
    title: 'AI流程图',
    target: graph,
    stencilGraphWidth: 200,
    // stencilGraphHeight: 180,
    collapsable: true,
    groups,
    layoutOptions: {
      columns: 1,
      columnWidth: 170,
      rowHeight: 55,
    },
  })


  //初始化
  for (let group in groupMap) {
    if (groupMap.hasOwnProperty(group)) {
      let nodeList = groupMap[group];
      let nodeGroupList = []
      for (let node of nodeList) {
        const r1 = createNodeWithTemplate(graph, node)
        nodeGroupList.push(r1)
      }
      stencil.load(nodeGroupList, group)
    }
  }
  document.getElementById('stencil-container')!.appendChild(stencil.container);
}

export const initGraph = (nodes: Model.NodeInfo[]) => {
  //注册节点
  register({
    shape: 'dag-node',
    width: 150,
    height: 36,
    component: AlgoNode,
    ports: {
      groups: {
        top: {
          position: 'top',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#C2C8D5',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        bottom: {
          position: 'bottom',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#C2C8D5',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
      },
    },
  })
  Graph.registerEdge(
    'dag-edge',
    {
      inherit: 'edge',
      attrs: {
        line: {
          stroke: '#C2C8D5',
          strokeWidth: 1,
          targetMarker: null,
        },
      },
    },
    true,
  )
  Graph.registerConnector(
    'algo-connector',
    (s, e) => {
      const offset = 4
      const deltaY = Math.abs(e.y - s.y)
      const control = Math.floor((deltaY / 3) * 2)

      const v1 = { x: s.x, y: s.y + offset + control }
      const v2 = { x: e.x, y: e.y - offset - control }

      return Path.normalize(
        `M ${s.x} ${s.y}
         L ${s.x} ${s.y + offset}
         C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${e.x} ${e.y - offset}
         L ${e.x} ${e.y}
        `,
      )
    },
    true,
  )

  const graph: Graph = new Graph({
    container: document.getElementById('graph-container')!,
    panning: {
      enabled: true,
      eventTypes: ['leftMouseDown', 'mouseWheel'],
    },
    mousewheel: {
      enabled: true,
      modifiers: 'ctrl',
      factor: 1.1,
      maxScale: 1.5,
      minScale: 0.5,
    },
    highlighting: {
      magnetAdsorbed: {
        name: 'stroke',
        args: {
          attrs: {
            fill: '#fff',
            stroke: '#31d0c6',
            strokeWidth: 4,
          },
        },
      },
    },
    connecting: {
      snap: true,
      allowBlank: false,
      allowLoop: false,
      highlight: true,
      connector: 'algo-connector',
      connectionPoint: 'anchor',
      anchor: 'center',
      validateMagnet({ magnet }) {
        return magnet.getAttribute('port-group') !== 'top'
      },
      createEdge() {
        return graph.createEdge({
          shape: 'dag-edge',
          attrs: {
            line: {
              strokeDasharray: '5 5',
            },
          },
          zIndex: -1,
        })
      },
    },
  })


  graph.on('edge:connected', ({ edge }) => {
    edge.attr({
      line: {
        strokeDasharray: '',
      },
    })
  })
  graph.on('node:dblclick', ({ node }) => {
    if (graph.isSelected(node)) {
      graph.unselect(node)
    } else {
      graph.select(node)
    }
  })
  graph.on('edge:dblclick', ({ edge }) => {
    if (graph.isSelected(edge)) {
      graph.unselect(edge)
    } else {
      graph.select(edge)
    }
  })
  graph.on('node:change:data', ({ node }) => {
    const edges = graph.getIncomingEdges(node)
    const { status } = node.getData() as NodeStatusPart
    edges?.forEach((edge) => {
      if (status === 'running') {
        edge.attr('line/strokeDasharray', 5)
        edge.attr('line/style/animation', 'running-line 30s infinite linear')
      } else {
        edge.attr('line/strokeDasharray', '')
        edge.attr('line/style/animation', '')
      }
    })
  })

  initStencil(graph, nodes)
  graph.use(new Clipboard({ enabled: true }))
  graph.use(
    new Selection({
      multiple: true,
      rubberEdge: true,
      rubberNode: true,
      modifiers: 'shift',
      rubberband: true,
      showNodeSelectionBox: true,
      showEdgeSelectionBox: true
    }),
  )
  graph.use(new Keyboard({ enabled: true, global: true }))
  createKeyboard(graph)
  graph.centerContent()
  return graph;
}


// 初始化节点/边
// const init = (data: Cell.Metadata[]) => {
//   const cells: Cell[] = []
//   data.forEach((item) => {
//     if (item.shape === 'dag-node') {
//       cells.push(graph.createNode(item))
//     } else {
//       cells.push(graph.createEdge(item))
//     }
//   })
//   graph.resetCells(cells)
// }
// // 显示节点状态
// const showNodeStatus = async (statusList: NodeStatus[][]) => {
//   const status = statusList.shift()
//   status?.forEach((item) => {
//     const { id, status } = item
//     const node = graph.getCellById(id)
//     const data = node.getData() as NodeStatus
//     node.setData({
//       ...data,
//       status,
//     })
//   })
//   setTimeout(() => {
//     showNodeStatus(statusList)
//   }, 3000)
// }
// init(data)
// showNodeStatus(nodeStatusList)
